package com.perceptivesoftware.licensing.server.rpc;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.perceptivesoftware.licensing.client.common.util.NPAction;
import com.perceptivesoftware.licensing.client.common.util.NPType;
import com.perceptivesoftware.licensing.client.common.util.PerceptivePermission;
import com.perceptivesoftware.licensing.client.common.util.Utils;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.role.RoleDTO;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.role.RoleNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.user.PermissionsSaveDTO;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.user.UserDTO;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.user.UserNavItem;
import com.perceptivesoftware.licensing.client.dto.SecurityTreeDTO;
import com.perceptivesoftware.licensing.client.rpc.SecurityService;
import com.perceptivesoftware.licensing.common.exceptions.PerceptiveLoginException;
import com.perceptivesoftware.licensing.dao.TwRolevalDaoExt;
import com.perceptivesoftware.licensing.dao.TwUservalDaoExt;
import com.perceptivesoftware.licensing.domain.generated.TwRolepriv;
import com.perceptivesoftware.licensing.domain.generated.TwRoleval;
import com.perceptivesoftware.licensing.domain.generated.TwUserval;
import com.perceptivesoftware.licensing.server.util.SecurityServiceUtil;
import com.perceptivesoftware.licensing.server.util.ServerUtil;
import com.perceptivesoftware.licensing.server.util.SessionServiceUtil;

/**
 * RPC entry point for admin tool enterprise hierarchy related services
 * 
 * <p/>
 * Copyright 2012 Perceptive Software
 * <p/>
 * Confidential and Proprietary
 * <p/>
 * Project: Perceptive Licensing
 * 
 */

@Service("securityService")
public class SecurityServiceImpl implements SecurityService
{

	@Autowired
	private SessionServiceUtil sessionServiceUtil;
	@Autowired
	private TwUservalDaoExt TwUservalDaoExt;
	@Autowired
	private TwRolevalDaoExt TwRolevalDaoExt;
	@Autowired
	private SecurityServiceUtil securityServiceUtil;

	@Override
	@Transactional
	public RoleNavItem createRole(final String name)
	{
		TwUserval curreTwUserval;
		try
		{
			curreTwUserval = sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		final TwRoleval roleval = new TwRoleval();
		roleval.setRolevalRoleCode(ServerUtil.genGUID());
		roleval.setRolevalRoleName(name);
		roleval.setRolevalDateCreated(new Timestamp((new Date()).getTime()));
		roleval.setTwUservalByRolevalCreatedBy(curreTwUserval);
		TwRolevalDaoExt.save(roleval);
		return new RoleNavItem(name, roleval.getRolevalRoleCode());
	}

	@Override
	@Transactional
	public UserNavItem createUser(final String inName, final String roleCode, final Boolean isSuper)
	{
		final String name = inName.toUpperCase();
		TwUserval currentUserval;
		try
		{
			currentUserval = sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		for (final TwUserval userval : TwUservalDaoExt.getNotDeletedUservals())
		{
			if (name.equalsIgnoreCase(userval.getUservalUserName()))
			{
				return null;
			}
		}
		String previousEmail = null;
		for (final TwUserval userval : TwUservalDaoExt.getNotDeletedUservals())
		{
			if (name.equals(userval.getUservalUserName()))
			{
				if (isSuper && Utils.isY(userval.getUservalSuper()))
				{
					return null;
				}
				previousEmail = userval.getUservalEmail();
			}
		}
		final TwUserval newUserval = new TwUserval();
		newUserval.setUservalId(ServerUtil.genGUID());
		newUserval.setUservalUserName(name.toUpperCase());
		newUserval.setUservalEmail(previousEmail);
		newUserval.setUservalSuper(Utils.getYOrNull(isSuper));
		TwUservalDaoExt.save(newUserval, currentUserval);
		if (!isSuper)
		{
			final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
			newUserval.setTwRoleval(roleval);
			TwUservalDaoExt.update(newUserval);
			for (final TwRolepriv rolepriv : roleval.getTwRoleprivs())
			{
				securityServiceUtil.addOrDeletePermissionFromUserPriv(newUserval.getUservalId(), NPType.getEnumForType(rolepriv.getId().getRoleprivPrivType()),
						NPAction.getEnumForAction(rolepriv.getId().getRoleprivPrivAction()), rolepriv.getId().getRoleprivItemCode(), true);
			}
		}
		return new UserNavItem(newUserval.getUservalUserName(), newUserval.getUservalId(), roleCode, isSuper);
	}

	@Override
	@Transactional
	public UserDTO getUserDTO(final String userCode)
	{
		final TwUserval userval = TwUservalDaoExt.findById(userCode);
		final UserDTO userDTO = new UserDTO(userCode);
		userDTO.setPermissionsDTO(securityServiceUtil.getPermissionsDTOForUserval(userval));
		userDTO.setEmail(userval.getUservalEmail());
		return userDTO;
	}

	@Override
	@Transactional
	public RoleDTO getRoleDTO(final String roleCode)
	{
		final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
		final RoleDTO roleDTO = new RoleDTO(roleval.getRolevalRoleCode());
		roleDTO.setPermissionsDTO(securityServiceUtil.getPermissionsDTOForRoleval(roleval));
		return roleDTO;
	}

	@Override
	@Transactional
	public UserDTO saveUserSettings(UserDTO user)
	{
		try
		{
			sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		final TwUserval userval = TwUservalDaoExt.findById(user.getUserCode());

		if (userval != null)
		{
			userval.setUservalEmail(user.getEmail());

			TwUservalDaoExt.update(userval);
		}

		TwUservalDaoExt.updateUserSettings(userval.getUservalUserName(), user.getEmail());

		return getUserDTO(user.getUserCode());
	}

	@Override
	@Transactional
	public PermissionsSaveDTO saveUserPermissions(final String userCode, final List<PerceptivePermission> dirtyPermissions)
	{
		String curreTwUserCode = null;
		try
		{
			curreTwUserCode = sessionServiceUtil.getCurrentUserval().getUservalId();
		}
		catch (final PerceptiveLoginException e)
		{

		}
		final PermissionsSaveDTO saveResults = new PermissionsSaveDTO();
		final TwUserval userval = TwUservalDaoExt.findById(userCode);
		for (final PerceptivePermission np : dirtyPermissions)
		{
			final NPType type = np.getType();
			final NPAction action = np.getAction();
			final Boolean hasPermission = np.getHasPermission();
			final String itemCode = np.getItemCode();
			securityServiceUtil.addOrDeletePermissionFromUserPriv(userCode, type, action, itemCode, hasPermission);
			if (userCode.equals(curreTwUserCode))
			{
				saveResults.setPrompt("Permission changes applied to user " + userval.getUservalUserName() + " will not take affect until the next time the user logs into the role.");
			}
		}
		if (saveResults.isSuccess())
		{
			TwUservalDaoExt.update(userval);
		}
		saveResults.setSuccess(true);
		return saveResults;
	}

	@Override
	@Transactional
	public PermissionsSaveDTO saveRolePermissions(final String roleCode, final List<PerceptivePermission> dirtyPermissions)
	{
		final PermissionsSaveDTO saveResults = new PermissionsSaveDTO();
		final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
		for (final PerceptivePermission np : dirtyPermissions)
		{
			final NPType type = np.getType();
			final NPAction action = np.getAction();
			final Boolean hasPermission = np.getHasPermission();
			final String itemCode = np.getItemCode();
			securityServiceUtil.addOrDeletePermissionFromRolePriv(roleCode, type, action, itemCode, hasPermission);
		}
		if (saveResults.isSuccess())
		{
			TwRolevalDaoExt.update(roleval);
		}
		saveResults.setSuccess(true);
		return saveResults;
	}

	@Override
	@Transactional
	public String deleteUser(final String userCode)
	{
		TwUserval curreTwUserval;
		try
		{
			curreTwUserval = sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		final TwUserval user = TwUservalDaoExt.findById(userCode);
		user.setUservalDeleted(new String("Y"));
		TwUservalDaoExt.update(user, curreTwUserval);
		return null;
	}

	@Override
	@Transactional
	public String deleteRole(final String roleCode)
	{
		TwUserval curreTwUserval;
		try
		{
			curreTwUserval = sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
		for (final TwUserval user : roleval.getTwUservals())
		{
			if (!Utils.isY(user.getUservalDeleted()))
			{
				return "This role still has users.";
			}
		}
		roleval.setRolevalDeleted(new String("Y"));
		TwRolevalDaoExt.update(roleval, curreTwUserval);
		return null;
	}

	@Override
	@Transactional
	public String renameRole(final String roleCode, final String newName)
	{
		TwUserval curreTwUserval;
		try
		{
			curreTwUserval = sessionServiceUtil.getCurrentUserval();
		}
		catch (final PerceptiveLoginException e)
		{
			return null;
		}
		final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
		for (final TwRoleval role : TwRolevalDaoExt.getNotDeletedRolevals())
		{
			if (role.getRolevalRoleName().toLowerCase().equals(newName.toLowerCase()))
			{
				return "A role with this name already exists.";
			}
		}
		roleval.setRolevalRoleName(newName);
		TwRolevalDaoExt.update(roleval, curreTwUserval);
		return null;
	}

	@Override
	@Transactional
	public PermissionsSaveDTO saveRolePermissions(final String roleCode, final List<PerceptivePermission> dirtyPermissions, final List<PerceptivePermission> cascadePermissions)
	{
		String currentUserCode = null;
		try
		{
			currentUserCode = sessionServiceUtil.getCurrentUserval().getUservalId();
		}
		catch (final PerceptiveLoginException e)
		{

		}
		final PermissionsSaveDTO saveResults = new PermissionsSaveDTO();
		final TwRoleval roleval = TwRolevalDaoExt.findById(roleCode);
		saveResults.setSuccess(true);
		if ((dirtyPermissions.size()) > 0)
		{
			if (!saveRolePermissions(roleval.getRolevalRoleCode(), dirtyPermissions).isSuccess())
			{
				saveResults.setSuccess(false);
			}
		}
		if ((cascadePermissions.size()) > 0)
		{
			for (final TwUserval userval : roleval.getTwUservals())
			{
				if (userval.getUservalId().equals(currentUserCode))
				{
					saveResults.setPrompt("Permission changes applied to user " + userval.getUservalUserName() + " will not take affect until the next time the user logs into the role.");
				}
				if (!saveUserPermissions(userval.getUservalId(), cascadePermissions).isSuccess() && !Utils.isY(userval.getUservalDeleted()))
				{
					saveResults.setSuccess(false);
				}
			}
		}
		return saveResults;
	}

	@Override
	@Transactional
	public void saveUserConfig(final String userCode, final UserDTO userDTO)
	{
		final TwUserval userval = TwUservalDaoExt.findById(userCode);
		TwUservalDaoExt.update(userval);
	}

	@Override
	@Transactional
	public SecurityTreeDTO getSecurityTreeDTO(String roleValCode)
	{
		return securityServiceUtil.getSecurityTreeDTO(roleValCode);
	}
}